#include"definicje.h"
#include"komunikator.h"
#include<stdlib.h>
#include<sys/select.h>
#include<string.h>
#include<stdio.h>
#include<error.h>
#include"protokol.h"
#include"ssl.h"
#ifdef DEBUG
#include<arpa/inet.h>
#endif

static struct elementListyK
{
   struct komunikator *k;
   struct elementListyK *nastepny;

} *komunikatory=NULL;

#ifdef DEBUG
void wypiszKomunikatory(void)
{
   struct elementListyK *element;
   struct sockaddr_in *adres;
   for(element=komunikatory; element!=NULL; element=element->nastepny)
   {
      adres=(struct sockaddr_in *)element->k->adres;
      if(adres!=NULL)
	      fprintf(stderr,"KOMUNIKATOR\n\tGniazdo:%i\n\tAdres:%"PRIx32":%"PRIx16"\n",element->k->gniazdo,ntohl(adres->sin_addr.s_addr),ntohs(adres->sin_port));
      else
	      fprintf(stderr,"KOMUNIKATOR\n\tGniazdo:%i\n\tAdres:NULL\n",element->k->gniazdo);
   }
}
#endif

int usunKomunikator(struct komunikator *k)
{
   struct elementListyK **kom=&komunikatory;
   struct elementListyK *aktualny;
#ifdef DEBUG
   fprintf(stderr,"Usuwam komunikator\n");
#endif

   if(*kom==NULL)
   {
      fprintf(stderr,"Nie znaleziono elementu\n");
      return -1;
   }
   while( (*kom)->k != k)
   {
      kom=&((*kom)->nastepny);
      if(*kom==NULL)
      {
	 fprintf(stderr,"Nie znaleziono elementu\n");
	 return -1;
      }
   }

   aktualny=(*kom);
   *kom=aktualny->nastepny;
   free(aktualny);
   return 0;
}

int dodajKomunikator(struct komunikator *nowy)
{
   struct elementListyK *aktualny;
#ifdef DEBUG
   fprintf(stderr,"Dodaje komunikator\n");
#endif
   aktualny=(struct elementListyK *)malloc(sizeof(struct elementListyK));
   if(aktualny==NULL)
   {
      fprintf(stderr,"Nie udało się zaalokować pamięci\n");
      return -1;
   }
   aktualny->k=nowy;
   aktualny->nastepny=komunikatory;
   komunikatory=aktualny;
   return 0;
}

int oczekujNaKomunikaty(struct komunikator ***k,unsigned int *ilosc)
{
   fd_set zbior;
   int wynik;
   int max=0;
   struct elementListyK *e;
#ifdef DEBUG
   fprintf(stderr,"Czekam na komunikaty\n");
#endif

   FD_ZERO(&zbior);
   for(e=komunikatory; e!=NULL; e=e->nastepny)
   {
      FD_SET(e->k->gniazdo,&zbior);
      max  =  e->k->gniazdo > max  ?  e->k->gniazdo  :  max;
   }
#ifdef DEBUG
   for(e=komunikatory; e!=NULL; e=e->nastepny)
   {
      if(FD_ISSET(e->k->gniazdo,&zbior))
      {
	 fprintf(stderr,"Gniazdo %i w zbiorze\n",e->k->gniazdo);
      }
      else
      {
	 fprintf(stderr,"Gniazdo %i nie w zbiorze\n",e->k->gniazdo);
      }
      max  =  e->k->gniazdo > max  ?  e->k->gniazdo  :  max;
   }
   fprintf(stderr,"max=%u\n",max);
#endif
   wynik=select(max+1,&zbior,NULL,NULL,NULL);
   if(wynik==-1)
   {
      perror("select");
      return -1;
   }
   *ilosc=wynik;
   *k=(struct komunikator **)malloc(sizeof(struct komunikator *)*wynik);
   if(*k==NULL)
   {
      fprintf(stderr,"Nie udało się zaalokować pamięci\n");
      return -1;
   }
   e=komunikatory;
   while(e!=NULL)
   {
      if(FD_ISSET(e->k->gniazdo,&zbior))
      {
	 (*k)[--wynik]=e->k;
      }
      e=e->nastepny;
   }
   return 0;
}

int przyjmijKomunikat(
      struct komunikator *k,
      struct sockaddr_storage **adres,
      int8_t **bufor
      )
{
   ssize_t rozmiar;
   socklen_t dlugosc;
   int wynik;
#ifdef DEBUG
   fprintf(stderr,"Przyjmuje komunikat\n");
#endif

   if(k->adres==NULL)
   {
#ifdef DEBUG
      fprintf(stderr,"Komunikator to komunikator zewnetrzny\n");
      fprintf(stderr,"Alokuje pamiec na bufor\n");
#endif
      *bufor=(int8_t *)malloc(sizeof(uint8_t)*MAX_PAKIET);
      if((*bufor)==NULL)
      {
	 fprintf(stderr,"Nie udało się zaalokować pamięci\n");
	 return -1;
      }
      *adres=(struct sockaddr_storage *)malloc(sizeof(struct sockaddr_storage));
      if((*adres)==NULL)
      {
	 free(bufor);
	 fprintf(stderr,"Nie udało się zaalokować pamięci\n");
	 return -1;
      }
#ifdef DEBUG
      fprintf(stderr,"Odbieram pakiet\n");
#endif
      //wynik=odbierzpakiet(k->gniazdo,*adres,*bufor);
      wynik=odbierzpakietSSL(k->gniazdo,*adres,*bufor,k->ssl,k->bio);
      if(wynik==-1)
      {
	 free(*bufor);
	 free(*adres);
	 return -1;
      }
   }
   else
   {
#ifdef DEBUG
      fprintf(stderr,"Komunikator to komunikator wewnetrzny\n");
      fprintf(stderr,"Odbieram pakiet\n");
#endif
      dlugosc=sizeof(struct sockaddr_storage);
      rozmiar=recv(k->gniazdo,bufor,sizeof(int8_t *),0);
      if(rozmiar!=sizeof(int8_t *))
      {
	 usunKomunikator(k);
	 return -1;
      }
      rozmiar=recv(k->gniazdo,adres,sizeof(struct sockaddr_storage *),0);
      if(rozmiar!=sizeof(struct sockaddr_storage *))
      {
	 usunKomunikator(k);
	 return -1;
      }

#ifdef DEBUG
      fprintf(stderr,"Odebrałem buforek: %p\n",*bufor);
      fprintf(stderr,"Odebrałem adresik: %p\n",*adres);
#endif
   }
   return 0;
}

int znajdzKomunikator(struct sockaddr_storage *adres,struct komunikator **kom)
{
   struct elementListyK *aktualny;
   aktualny=komunikatory;
#ifdef DEBUG
   fprintf(stderr,"Szukam komunikatora\n");
   fprintf(stderr,"Wchodzę do pętli\n");
   wypiszKomunikatory();
   unsigned int i=0;
#endif
   for(aktualny=komunikatory; aktualny != NULL; aktualny=aktualny->nastepny)
   {
#ifdef DEBUG
      fprintf(stderr,"iteracja %u\n",++i);
#endif
      if(
	    aktualny->k->adres==adres ||
	    (
	     aktualny->k->adres!=NULL &&
	     adres != NULL &&
	     memcmp(aktualny->k->adres,adres,sizeof(struct sockaddr_storage))==0
	    )
	)
      {

#ifdef DEBUG
	 fprintf(stderr,"Znalazłem adres\n");
#endif
	 *kom=aktualny->k;
	 return 0;
      }
   }
   return -1;
}

int wyslijKomunikat(
      struct komunikator *k,
      struct sockaddr_storage *adres,
      int8_t *bufor)
{
   int8_t *wskaznik;
   ssize_t rozmiar;
   socklen_t dlugosc;
   int wynik;
#ifdef DEBUG
   fprintf(stderr,"Wysyłam komunikat\n");
#endif
   if(k->adres==NULL)
   {
      //wynik=wyslijpakiet(k->gniazdo,adres,bufor);
      wynik=wyslijpakietSSL(k->gniazdo,adres,bufor,k->ssl,k->bio);
      free(bufor);
      if(wynik==-1)
      {
	 return -1;
      }
   }
   else
   {
      rozmiar=send(k->gniazdo,&bufor,sizeof(int8_t *),MSG_DONTWAIT);
      if(rozmiar!=sizeof(int8_t *))
      {
	 usunKomunikator(k);
	 return -1;
      }
      rozmiar=send(k->gniazdo,&adres,sizeof(struct sockaddr_storage *),MSG_DONTWAIT);
      if(rozmiar!=sizeof(struct sockaddr_storage *))
      {
	 usunKomunikator(k);
	 return -1;
      }
#ifdef DEBUG
      fprintf(stderr,"Wysłałem buforek: %p\n",bufor);
      fprintf(stderr,"Wysłałem adresik: %p\n",adres);
#endif
   }
   return 0;
}

